﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;

namespace Microsoft.Coding4Fun.TweetCraft
{
    public sealed class TraceScope : IDisposable
    {
        private readonly TraceLevel traceLevel;
        private readonly Stopwatch stopwatch;
        private bool completed;

        private TraceScope(TraceLevel traceLevel)
        {
            this.traceLevel = traceLevel;
            Trace.Indent();

            // Initialize the stopwatch and start it
            stopwatch = new Stopwatch();
            stopwatch.Start();
        }

        /// <summary>
        /// Completes a <see cref="TraceScope"/>.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="args">The arguments.</param>
        public void Complete(string message, params object[] args)
        {
            if (completed)
                throw new InvalidOperationException();

            Trace.Unindent();

            // Stop stopwatch upon completion
            stopwatch.Stop();

            string durationMessage = String.Format(CultureInfo.CurrentCulture, " ({0})", stopwatch.Elapsed);

            switch (traceLevel)
            {
                case TraceLevel.Info:
                    TraceInformation(message + durationMessage, args);
                    break;
            }

            completed = true;
        }

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            if (!completed)
                this.Complete("Complete.");

            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Creates a new <see cref="TraceScope"/> using <see cref="TraceLevel.Info"/>
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="args">The arguments.</param>
        /// <returns></returns>
        public static TraceScope Information(string message, params object[] args)
        {
            if (message == null)
                throw new ArgumentNullException("message");

            // Trace the message and its arguments
            TraceInformation(message, args);

            // Return a new trace scope
            return new TraceScope(TraceLevel.Info);
        }

        private static void TraceInformation(string message, params object[] args)
        {
            //// Create a stack trace and prefix the message with the calling type's name
            //var stackTrace = new StackTrace();
            //string callingTypeNamePrefix = String.Format(CultureInfo.CurrentCulture, "{0}: ", stackTrace.GetFrame(2).GetMethod().DeclaringType.Name);
            
            // Perform the actual trace
            Trace.TraceInformation(message, args);
        }
    }
}